#ifndef QGLSURFACES_RENDERER_H

//--------------------------------------------------------
//		DEFINITIONS
//--------------------------------------------------------

#define QGLSURFACES_RENDERER_H
#define ZOOM_BORDER_SIZE 30
#define SELECT_DELAY_SEC 0.1
#define VERT_SELECT_THRESHOLD 0.05
#define EDGE_SELECT_THRESHOLD 0.05
#define FACE_STRETCH_FACTOR	0.05
#define ZOOM_RAD_STEPS 10
#define ZOOM_STEP_SIZE 0.1
#define CVITER PolyMesh::ConstVertexIter
#define CFITER PolyMesh::ConstFaceIter
#define CEITER PolyMesh::ConstEdgeIterator
#define CHITER PolyMesh::ConstHalfedgeIter
#define onMouseMove mouseMoveEvent
#define onMouseDown mousePressEvent
#define onMouseUp mouseReleaseEvent
#define onWheelScroll wheelEvent
#define onGLWindowResize resizeGL
#define onMouseDoubleClick mouseDoubleClickEvent 

// definitions for rendering modes
#define RENDER_TOOL		 0
#define RENDER_FLAT		 1
#define RENDER_SMOOTH	 2

//--------------------------------------------------------
//		INCLUDES
//--------------------------------------------------------

#include <OpenMesh/Core/Geometry/VectorT.hh>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <QFileDialog>
#include <QMouseEvent>
#include <qmenu.h>
#include <QtOpenGL/qgl.h>
#include <glut.h>
#include <string>
#include <vector>
#include <time.h>
#include <map>
#include "EventDispatcher.h"
#include "ModelLocator.h"
#include "ModelFrame.h"
#include "CatmullSubdivider.h"
#include "LoopSubdivider.h"
#include "RendererHistoryEvent.h"
#include "util.h"




//--------------------------------------------------------
//		CLASS: QGLSurfacesRenderer
//--------------------------------------------------------

class QGLSurfacesRenderer: public QGLWidget, EventDispatcher
{	
    Q_OBJECT

public:

	//Construction/destruction
	QGLSurfacesRenderer			( QWidget* parent );
	~QGLSurfacesRenderer		( );

	void initTransformations	( ModelFrame* frame );
	void zoomToMesh				( const PolyMesh& target );
	void setModelFrame			( ModelFrame* );
	void setRenderMode			( int mode );
	void reverseEvent			( Event* );
	void centerModel			( bool = true );
	void setReconnectedOpacity	( double opacity );

signals:

	void objectSelected			( const Selection* );
	void clearSharpEdges		( );
	void setAnimateSliderValue	( int );
	void startZoomAnimation		( );
	void stopZoomAnimation		( );

public slots:

	void onModelLoaded				(  );
	void onModelImportanceChanged	(  );
	void activateSelection			( SelectType type );
	void animateSliderChanged		( int changedVal );
	void animateZoom				(  );
 
protected:

	//Initialization functions
	void initializeGL		( );				// initialize OpenGL states (triggered by Qt)
	void onGLWindowResize	( int w, int h );	// handle resize events (triggered by Qt)
	void setDefaultLight	( void );			// setup lighting
	void initQT				( );
	void brightenLights		( );
	void dimLights			( );

	//Rendering functions
	void paintGL			( ); // draw the scene (triggered by Qt) 

	//Event handlers
	void onMouseDown	    ( QMouseEvent* );
	void onMouseUp	        ( QMouseEvent* );
	void onMouseMove		( QMouseEvent* );
	void onWheelScroll	    ( QWheelEvent* );
	void onMouseDoubleClick ( QMouseEvent* ); 

private:

	//Class attributes:
	bool			animating;
	bool			zooming;
	bool			zoomComplete;
	bool			mouseMoved;
	int				renderMode;
	double			reconMeshOpacity;
	clock_t			nextSelectionTime;
	SelectType		selectionMode;
	ModelFrame*		modelFrame; 
	Selection*		selection;
	Selection*		selectionHover;
	Qt::CursorShape	lastKnownCursor;

	Vec3f			centerPoint; 
	Vec3f			sideP1, sideP2;
	Sphere			bounds;
	Sphere			oldBounds;
	Vec3d			zoomDisplacement;
	double			scale;
	double			radiusInc;
	Sphere			interpBounds;
	double			zoomInterpVal;
	RendererHistoryEvent*	testEvent;
			

	//Selection
	void			doSelection			( const Vec3d& windowPoint );
	void			doHoverSelection	( const Vec3d& windowPoint );
	VertexHandle	getVertexSelection	( const PolyMesh& mesh, const Vec3d& worldPoint, const Vec3d& rayDirection );
	EdgeHandle		getEdgeSelection	( const PolyMesh& mesh, const Vec3d& worldPoint, const Vec3d& rayDirection );
	FaceHandle		getFaceSelection	( const PolyMesh& mesh, const Vec3d& worldPoint, const Vec3d& rayDirection, bool stretchFaces);

	//Projection/unprojection
	void			unprojectRay		( const Vec3d& windowPoint, Vec3d& rayOrigin, Vec3d& rayDirection);
	void			unprojectPoint		( Vec3d& windowPoint, const double distance );
	void			projectPoint		( Vec3d& worldPoint );

	//Geometric utils
	Sphere&			getBoundsSphere		( const PolyMesh& source );
	bool			isInsideCurve		( const Vec3d& testPoint, const std::vector<Vec3d> polygon, int ignoredAxis );
	bool			isPolygonHit		( const Vec3d& rayOrigin, const Vec3d& rayDirection, 
		                                  const std::vector<Vec3d>& polygon, double& coefficient);

	//Rendering
	void			drawFrame			( );
	void			renderToolMode		( );
	void			renderAnimationMode	( );
	void			renderSmoothMode	( );
	void			renderFlatMode		( );
	void			drawMesh			( PolyMesh* mesh );
	void			drawGhostMesh		( PolyMesh* mesh );
	void			drawHoverSelection	( );
	void			drawSharpEdges		( PolyMesh* mesh );
	void			drawWeights			( PolyMesh* mesh );
	string          weightToFraction    (double theWeight);

	//Animation
	double			interpVal;
};

#endif 
